/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.ipti.br.tag.dao;

import org.ipti.br.tag.bean.dataManipulation.SelectionElement;
import org.ipti.br.tag.entity.Actor;
import org.ipti.br.tag.entity.Actor_;
import org.ipti.br.tag.entity.Campaign;
import org.ipti.br.tag.entity.Campaign_;
import org.ipti.br.tag.entity.Hb;
import org.ipti.br.tag.entity.Hb_;
import org.ipti.br.tag.entity.Human;
import org.ipti.br.tag.entity.Human_;
import org.ipti.br.tag.entity.Unity;
import org.ipti.br.tag.entity.Unity_;
import java.io.Serializable;
import java.util.Calendar;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;

/**
 *
 * @author FelipeMSX
 */
@Stateless
public class HbFacade extends AbstractFacade<Hb> implements Serializable {

    @PersistenceContext(unitName = "TAG2PU")
    private EntityManager em;

    @Override
    protected EntityManager getEntityManager() {
        return em;
    }

    public HbFacade() {
        super(Hb.class);
    }

    /*
     * Trazer todos os Hbs filtrando por Unidade e Campaign
     */
    public List<Hb> listAllHb(Unity unity, Campaign campaign) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Hb> cq = cb.createQuery(Hb.class);
        Root<Hb> rt = cq.from(Hb.class); 
        
        Predicate p1 = cb.equal( rt.join(Hb_.human).join(Human_.actors).join(Actor_.unity).get(Unity_.id), unity.getId());
        Predicate p2 = cb.equal( rt.join(Hb_.campaign).get(Campaign_.id), campaign.getId() ); 
        
        cq.where( cb.and( p1,p2 ) );
        try {
            return getEntityManager().createQuery(cq).getResultList();
        } catch(NoResultException e) {
            e.printStackTrace();
            return null;
        }
    
    }
    public List<Human> searchActivatedHuman(Unity unity, Campaign campaign) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Human> cq = cb.createQuery(Human.class);
        Root<Hb> rt = cq.from(Hb.class);
        Join<Hb, Human> humans = rt.join(Hb_.human);
        Join<Human, Actor> actors = humans.join(Human_.actors);
        
        Predicate p1 = cb.equal(rt.join(Hb_.campaign).get(Campaign_.id), campaign.getId());
        
        Predicate p2 = cb.equal(actors.join(Actor_.unity).get(Unity_.id), unity.getId());
        Predicate p3 = cb.lessThanOrEqualTo(actors.get(Actor_.activated), Calendar.getInstance());
        Predicate p4 = cb.or(
                    cb.greaterThanOrEqualTo(actors.get(Actor_.deactivated), Calendar.getInstance()),
                    cb.isNull(actors.get(Actor_.deactivated)));
        
        cq.where(p1, p2, p3, p4);

        cq.distinct(true);
        cq.orderBy(cb.asc(humans.get(Human_.firstName)),
                        cb.asc(humans.get(Human_.lastName)));
        
        return getEntityManager().createQuery(cq).getResultList();
    }
    
    public List<Human> listHumans(Unity unity, Campaign campaign) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Human> cq = cb.createQuery(Human.class);
        Root<Hb> root = cq.from(Hb.class);
        
        cq.select(root.join(Hb_.human));
        
        Predicate p1 = cb.equal(root.join(Hb_.campaign).get(Campaign_.id), campaign.getId());
        Predicate p2 = cb.equal(root.join(Hb_.human).join(Human_.actors).join(Actor_.unity).get(Unity_.id), unity.getId());
        
        cq.where(p1, p2).distinct(true);
        
        try {
            return getEntityManager().createQuery(cq).getResultList();
        } catch (NoResultException e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public List<Hb> findAllHb(Human human, Campaign campaign) {  //OBS
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Hb> cq = cb.createQuery(Hb.class);
        Root<Hb> root = cq.from(Hb.class);
        
        Predicate p1 = cb.equal(root.join(Hb_.campaign).get(Campaign_.id),  campaign.getId());
        Predicate p2 = cb.equal(root.join(Hb_.human).get(Human_.id), human.getId());
        
        cq.where( p1,p2);
       
//        cq.orderBy( cb.asc(root.get(Hb_.creationDate)));
        try{
            return getEntityManager().createQuery(cq).getResultList();
        }catch(NoResultException e){
            e.printStackTrace();
            return null;
        }
    }
    
    public Long countHbs(long humanID, long campaignID){
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Long> cq = cb.createQuery(Long.class);
        Root<Hb> root = cq.from(Hb.class);
        
        cq.select(cb.countDistinct(root));
        
        Predicate p1 = cb.equal( root.join(Hb_.human).get(Human_.id), humanID);
        Predicate p2 = cb.equal(root.join(Hb_.campaign).get(Campaign_.id), campaignID);
        
        cq.where(p1,p2);
       
        try{
            return getEntityManager().createQuery(cq).getSingleResult();
        } catch(NoResultException e) {
            e.printStackTrace();
            return 0L;
        }
    }
    
    public Hb getLastMeasure(Human human) { //OBS
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Hb> cq = cb.createQuery(Hb.class);
        Root<Hb> rt = cq.from(Hb.class);
        
        Subquery<Calendar> subQ = cq.subquery(Calendar.class);
        Root<Hb> subRt = subQ.from(Hb.class);
        subQ.where(cb.equal(subRt.get(Hb_.human).get(Human_.id), rt.get(Hb_.human).get(Human_.id)));
        
        cq.where(cb.equal(rt.get(Hb_.human).get(Human_.id), human.getId()));

        cq.distinct(true);
        try {
            return getEntityManager().createQuery(cq).getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }
    
    public Hb findBy(Human human, Campaign campaign, int ordenation) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Hb> cq = cb.createQuery(Hb.class);
        Root<Hb> rt = cq.from(Hb.class);
        
        Predicate p1,p2,p3;
        p1 = cb.equal(rt.get(Hb_.human).get(Human_.id), human.getId());
        p2 = cb.equal(rt.get(Hb_.campaign).get(Campaign_.id), campaign.getId());
        p3 = cb.equal(rt.get(Hb_.ordernation), ordenation);
        cq.where(p1,p2,p3);

        try {
            return getEntityManager().createQuery(cq).getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }
    
    public List<Hb> modifiedPerfFreqBetweenDate(Calendar initialDate, Calendar finalDate, Long serialNumber) {
        CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
        CriteriaQuery<Hb> cq = cb.createQuery(Hb.class);
        Root<Hb> from = cq.from(Hb.class);
        Predicate predicate1 = cb.notEqual(from.get(Hb_.serialNumber), serialNumber);
        Predicate predicate2 = cb.greaterThanOrEqualTo(from.get(Hb_.lastModified), initialDate);
        Predicate predicate3 = cb.lessThan(from.get(Hb_.lastModified), finalDate);
        cq.where(cb.and(predicate1, predicate2, predicate3));

        return getEntityManager().createQuery(cq).getResultList();
    }
}
